class_name Player extends CharacterBody2D

############## 基本变量
# 超人模式
@export var is_super_man:bool = false

# 重力与常规速度
var gravity:float = 2000 # ProjectSettings.get_setting("physics/2d/default_gravity") * 2
var speed = 350

# 0.2秒加到最大速度
var accelerate = speed / 0.2 

# 精灵
@onready var sprite = $Sprite
@onready var animation_player = $AnimationPlayer

# 脸面朝向 1:右边 -1:左边
@export var face_direction:int = 1

############## 跳跃相关 
# 起跳速度
const jump_force:float = 900
# 按压时长
#var jump_pressed_time:float = 0 
# 从跳跃速度到为0所消耗的时间 v = gt  -900 = 2000*t 
var jump_max_time:float = jump_force/gravity
# 跳跃次数，最多2次。落在地板，天花板，墙才可以重置
var jump_num = 0
# 用于可提前发起起跳请求 - 例如在落地之前按下起跳键，在落地时即可起跳 - 手感丝滑
@onready var jump_request_timer:Timer = $Timers/JumpRequestTimer
@onready var jump_sound:AudioStreamPlayer2D = $Sound/JumpSound

#################### 坠落状态
# 郊狼时间: 用于在离开地板一段时间后仍然可跳
@onready var coyote_timer:Timer = $Timers/CoyoteTimer

#################### 冲锋
@onready var charge_timer:Timer = $Timers/ChargeTimer
# 冲刺次数; 最大1
var charge_num:int = 0
@export var charge_max_num:int = 1

#################### 死亡计时
var dead_time:float = 0

#################### 抓天花板
var prepare_catch_celling:bool = false

################### 墙
# 最后一次抓住墙的方向
var wall_direction = 0

##################### 射线
@onready var ray_forward:RayCast2D = $Boxes/RayForward
var ray_direct_right = 50*Vector2.RIGHT
var ray_direct_left = 50*Vector2.LEFT
var ray_direct_up = 50*Vector2.UP
var ray_direct_down = 50*Vector2.DOWN

################## 伤害与受伤
@onready var hit_box = $Boxes/HitBox
@onready var hurt_box = $Boxes/HurtBox

######################################################### end 变量设置

######################################################## start 有限状态机
@onready var play_status_manage = $PlayStatusManage


func _ready():
	_force_face_direction(face_direction)

# 动画，使之更加生动有趣
func _tween_scale(target):
	var tween:Tween
	tween = get_tree().create_tween()
	tween.set_parallel(false)
	tween.set_ease (Tween.EASE_IN_OUT)
	#tween.set_trans(Tween.TRANS_BACK )
	tween.tween_property(sprite, "scale", target, 0.05)
	tween.tween_property(sprite, "scale", Vector2(1,1), 0.1)

# 动画，使之更加生动有趣
func _tween_scale_color(target):
	var tween:Tween
	tween = get_tree().create_tween()
	tween.set_parallel(false)
	tween.set_ease (Tween.EASE_IN_OUT)
	#tween.set_trans(Tween.TRANS_BACK )
	tween.tween_property(sprite,"modulate",Color(1.0,1.0,0.0,0.2), 0.01)
	tween.tween_property(sprite, "scale", target, 0.01)
	tween.tween_property(sprite,"modulate",Color.WHITE, 0.04)
	tween.tween_property(sprite, "scale", Vector2(1,1), 0.15)
# 自由落地运动
func common_velocity(delta):
	var direction = get_direction()
	velocity.y += gravity * delta
	velocity.x = move_toward(velocity.x, direction * speed, accelerate * delta)
	return direction

func show_animiation(name):
	animation_player.play(name)

func can_jump_from_wall() -> int:
	if is_on_wall() && jump_request_timer.time_left>0:
		# 从墙上发起跳跃
		velocity.x = wall_direction * speed * 1.2
		_to_jump_status()
		return 1
	return 0

func can_jump() -> int:
	var can_jump = is_on_floor() or coyote_timer.time_left>0
	if can_jump && jump_request_timer.time_left>0:
		_to_jump_status()
		return 1
	elif jump_num < 2 && jump_request_timer.time_left>0:
		_to_jump_second_status()
		return 2
	return 0
	
func can_second_jump() -> int:
	if jump_num < 2 && jump_request_timer.time_left>0:
		_to_jump_second_status()
		return 2
	return 0

# 一段跳
func _to_jump_status() -> void:
	if jump_num >= 3:
		return
	_to_jump()

# 两段跳
func _to_jump_second_status() -> void:
	if jump_num >= 3:
		return
	jump_num = 2
	_to_jump()
	
func _to_jump() -> void:
 
	jump_request_timer.stop()
	coyote_timer.stop()
	
	jump_num += 1
	velocity.y = -jump_force
	_tween_scale(Vector2(1/1.25,1.25))
	
	#3. 播放动画
	jump_sound.play()

func _reset_jump_num():
	jump_num = 0

func _reset_charge_num():
	charge_num = 0

func _to_falling_status():
	coyote_timer.start()
	play_status_manage.to_fall()

func can_jump_from_celling():
	if is_on_ceiling() && jump_request_timer.time_left>0:
		# 从天花板上
		_to_falling_from_celling()
		return 1
	return 0

# 天花板上跳 - 跌落状态
func _to_falling_from_celling():
	jump_request_timer.stop()
	coyote_timer.stop()
	
	jump_num = 1
	velocity.y = jump_force
	_tween_scale(Vector2(1/1.25,1.25))

# 进入冲锋状态
func _to_charge_status_from_wall():
	_set_face_direction(wall_direction)
	_to_charge_status()
	
func _to_charge_status():
	# 转为状态
	play_status_manage.to_charge()
	
	charge_num +=1
	charge_timer.start()
	
	var direction = -1 if sprite.flip_h else 1	
	velocity = Vector2(speed * 5 * direction, -10)
	
	_tween_scale_color(Vector2(0.5,0.5))
	_super_time()

# 冲锋：时间结束
func _on_charge_timer_timeout():
	velocity.x = 0
	_normal_time()

# 冲锋：无敌时刻
func _super_time():
	hit_box.monitoring = false
	hurt_box.monitorable = false
	self.set_collision_layer_value(2,false)
	self.set_collision_mask_value(3,false)

# 冲锋：回归正常时刻
func _normal_time():
	hit_box.monitoring = true
	hurt_box.monitorable = true
	self.set_collision_layer_value(2,true)
	self.set_collision_mask_value(3,true)

# 死亡状态
func _to_death_status():
	velocity.y = -jump_force / 2.0
	play_status_manage.to_death()
	animation_player.play("death")
	
# 按键设置
# 玩家控制左右方向
func get_direction():
	var direction = Input.get_axis("left", "right")
	_set_face_direction(direction)
	return direction
	
# 脸面朝向
func _set_face_direction(direction):
	# 朝向
	if direction == 0:
		return
		
	if direction == face_direction:
		return
		
	#if direction != 1 && direction != -1:
		#direction = 1
		
	_force_face_direction(direction)
	
func _force_face_direction(direction):
	face_direction = direction
	
	# 精灵朝向
	sprite.flip_h = direction < 0
	
	#射线朝向
	if direction > 0:
		ray_forward.set_target_position(ray_direct_right)
	else:
		ray_forward.set_target_position(ray_direct_left)

func _unhandled_input(event):
	if play_status_manage.is_death() :
		return
	
	# 长跳
	if  event.is_action_pressed("jump"):
		#jump_pressed_time = 0
		jump_request_timer.start()

	# 短跳
	if jump_num < 3 && event.is_action_released("jump") and velocity.y < -jump_force / 2.0:
		velocity.y = -jump_force / 2.0
		#if jump_pressed_time < jump_max_time:
			# 百分比跳跃
			#velocity.y = -jump_force * jump_pressed_time / jump_max_time
	# 冲锋
	
	if not play_status_manage.is_charge() && not play_status_manage.is_celling() && charge_num < charge_max_num && event.is_action_pressed("mouse_right"):
		if play_status_manage.is_onwall():
			_to_charge_status_from_wall()
		else:
			_to_charge_status()
	
	## 下墙或下天花板
	if  event.is_action_pressed("down"):
		if play_status_manage.is_celling():
			velocity.y = 0
			_to_falling_status()
		if play_status_manage.is_onwall():
			velocity.x = 0
			_to_falling_status()
			
	## 下墙或下天花板
	if  event.is_action_pressed("up"):
		if not play_status_manage.is_celling():
			prepare_catch_celling = true
			
	if  event.is_action_released("up"):
		prepare_catch_celling = false
			

# 被别人击中
func _on_hurt_box_hurt(_hit_box):
	if is_super_man:
		print("oauch")
		return

	_to_death_status()
	#Engine.time_scale = 0.5
	await $AnimationPlayer.animation_finished
	Global.reload_world()

# 击中敌人
func _on_hit_box_hit():
	velocity.y = -jump_force / 2.0
	if not is_on_floor():
		_tween_scale(Vector2(1.25,1/1.25))

func is_collision_wall():
	# 墙上时刻
	if not is_on_wall_only():
		return false
	
	#var colider = get_last_slide_collision()
	#if colider==null:
		#return false
		
	wall_direction = get_wall_normal().x
	var ray_direction =  ray_forward.target_position.x
	if ray_direction *  wall_direction < 0:
		var is_find = ray_forward.is_colliding()
		if is_find:
			return true
			
	return false

func is_collision_celling():
	if is_on_ceiling_only():
		if prepare_catch_celling:
			return true
	return false

func move_and_collision_info():
	var collision_info = get_collision_info()
	reset_nums(collision_info)
	is_just_to_floor(collision_info)
	return collision_info

# 刚刚落地
func is_just_to_floor(collision_info):
	if not collision_info.get("was_on_floor") and collision_info.get("is_on_floor"):
	# 落地时刻: 曾经不地上，但是现在在地上
		_tween_scale(Vector2(1.25,1/1.25))

func get_collision_info():
	var info :Dictionary
	info.was_on_floor = is_on_floor()
	info.was_on_wall = is_on_wall()
	info.was_on_celling = is_on_ceiling_only()
	
	move_and_slide()
	
	info.is_on_floor = is_on_floor()
	info.is_on_wall = is_on_wall()
	info.is_on_celling = is_on_ceiling_only()
	
	return info

func reset_nums(collision_info:Dictionary):
	if collision_info.get("was_on_floor") || collision_info.get("was_on_wall"):
		_reset_jump_num()
		_reset_charge_num()
		
	if collision_info.get("was_on_celling")  :
		_reset_jump_num()

	# 地面上时刻
	if collision_info.get("is_on_floor"):
		_reset_jump_num()
		_reset_charge_num()

func slide_on_wall():
	# 从墙上向下滑
	var direction = get_direction()
	if direction == 0:
		# 给予一个与墙相反的速度，以产生持续碰撞
		velocity.x = clamp(-wall_direction * speed / 10.0,-30,30)
	else:
		velocity.x = direction * speed
	
	# 以缓慢的速度向下坠落
	velocity.y = speed / 4.0
	
func is_not_on_wall():
	# 如果挂不在墙上
	return ray_forward.target_position.x * wall_direction > 0

func walk_from_celling(): 
	var direction = get_direction()
	velocity.x = direction * speed / 2.0
	velocity.y = -10
	 
